﻿using System.Collections.Generic;
using System.Windows.Media.Media3D;
using LFSRecord2.Model.Undo;
using LFSRecord2.Structures;
using System.Diagnostics;
using LFSRecord2.Model.Replay;

namespace LFSRecord2.Model
{
    public class CompLayerPropertyPoint3DRD : CompLayerPropertyPoint3D
    {
        public new Point3D DefaultValue { get; private set; }
        public new bool HasAnimationPath { get; private set; }

        private double _currentXValue = 0;
        public new double CurrentXValue
        {
            get { return (double)_currentXValue; }
            set
            {
                _currentXValue = value;
                OnPropertyChanged("CurrentXValue");
            }
        }
        private double _currentYValue = 0;
        public new double CurrentYValue
        {
            get { return (double)_currentYValue; }
            set
            {
                _currentYValue = value;
                OnPropertyChanged("CurrentYValue");
            }
        }
        private double _currentZValue = 0;
        public new double CurrentZValue
        {
            get { return (double)_currentZValue; }
            set
            {
                _currentZValue = value;
                OnPropertyChanged("CurrentZValue");
            }
        }

        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
        }

        public CompLayerPropertyPoint3DRD(CompLayerBase parentLayer, int propertyIndex, string propertyName, Point3D defaultValue, LayerPropertyValueMeaning propertyValueMeaning)
            : base(parentLayer, propertyIndex, propertyName, defaultValue, propertyValueMeaning, false)
        {
            IsEditable = false;
        }

        public override void HandleNewPropertyBinding(CompLayerPropertyBase prop)
        {
        }

        public override void RemoveCurrentValueListener()
        {
        }

        public override CustomKeyFrame SetKeyAtCurrentTime(int frame)
        {
            return null;
        }

        public override void AddKeyFrame(CustomKeyFrame key)
        {
        }
        public override void AddKeyFrame(CustomKeyFrame key, bool autoBezier)
        {
        }

        public override void DeleteAllKeyframes()
        {
        }

        public override object GetValueAtFrame(int frame)
        {
            // Get a reference to our ReplayPlayerData object and replay time offset
            CompLayerReplayData l = (CompLayerReplayData)ParentLayer;
            ReplayPlayerData pData = l.CurrentReplayPlayerData(frame);
            double replayTime = l.CurrentReplayTimeOffset(frame);

            if (pData == null || pData.FirstMciNode() == null)
                return new Point3D();

            // Find the data packets between which to interpolate
            ReplayDataNode fromNode = pData.FirstMciNode(), toNode = null;
            
            // Time is before first mci datanode
            if (replayTime < fromNode.ReplayTime)
                return new Point3D(fromNode.MciInfo.X / 65535.0d, -fromNode.MciInfo.Y / 65535.0d, fromNode.MciInfo.Z / 65535.0d);

            foreach (ReplayDataNode rNode in pData.DataNodes)
            {
                if (!rNode.IsMciNode)
                    continue;

                if (replayTime < rNode.ReplayTime)
                {
                    toNode = rNode;
                    if (fromNode == null)
                        fromNode = rNode;
                    break;
                }
                fromNode = rNode;
            }

            // Hold value? (time is beyond last datanode)
            if (toNode == null)
                return new Point3D(fromNode.MciInfo.X / 65535.0d, -fromNode.MciInfo.Y / 65535.0d, fromNode.MciInfo.Z / 65535.0d);

            replayTime -= fromNode.ReplayTime;
            double timeInterval = toNode.ReplayTime - fromNode.ReplayTime;

            return CustomPoint3DInterpolation.InterpolateLinear(
                new Point3D(fromNode.MciInfo.X / 65535.0d, -fromNode.MciInfo.Y / 65535.0d, fromNode.MciInfo.Z / 65535.0d),
                new Point3D(toNode.MciInfo.X / 65535.0d, -toNode.MciInfo.Y / 65535.0d, toNode.MciInfo.Z / 65535.0d),
                replayTime / timeInterval);
        }

        public override CustomKeyFrame OnCurrentValueChange()
        {
            return null;
        }

        public override bool SetCurrentValue(int frame)
        {
            Point3D p = (Point3D)GetValueAtFrame(frame);
            if (CurrentXValue == p.X && CurrentYValue == p.Y && CurrentZValue == p.Z)
                return false;

            CurrentXValue = p.X;
            CurrentYValue = p.Y;
            CurrentZValue = p.Z;

            return true;
        }

        public override PropertyDataBase DataStructure()
        {
            Debug.WriteLine("Creating Point3D RD Property Datastructure");

            PropertyPoint3DData propertyData = new PropertyPoint3DData()
            {
                ParentLayerIndex = ParentLayer.LayerIndex,
                PropertyIndex = PropertyIndex,
                IsEditable = IsEditable,
                IsSelected = IsSelected,
                IsAnimated = IsAnimated,
                ValueLock = ValueLock,
                BindingPropertyIndex = BindingPropertyIndex,
                BoundPropertyIgnoreParent = BoundPropertyIgnoreParent,
                NumKeyFrames = KeyFrames.Count,
                KeyFrames = new KeyFrameDataBase[KeyFrames.Count],

                HasAnimationPath = HasAnimationPath,
                CurrentXValue = _currentXValue,
                CurrentYValue = _currentYValue,
                CurrentZValue = _currentZValue
            };

            return propertyData;
        }
    }
}
